package com.fiberhome.nas.feature.common.manager

import android.content.Context
import com.fiberhome.nas.core.data.repository.PhotoRepository
import com.fiberhome.nas.core.data.repository.TaskCenterRepository
import com.fiberhome.nas.core.model.entity.AlbumInfo
import com.fiberhome.nas.core.model.entity.LocalMediaItem
import com.fiberhome.nas.core.model.entity.TaskStatus
import com.fiberhome.nas.core.model.entity.UploadTask
import com.fiberhome.nas.core.model.request.UploadRequest
import com.fiberhome.nas.core.result.ResultHandler
import com.fiberhome.nas.core.result.asResult
import com.fiberhome.nas.core.util.file.FileUtils
import com.fiberhome.nas.core.util.log.LogUtils
import com.fiberhome.nas.core.util.media.MediaConverter
import com.fiberhome.nas.core.util.time.formatToDuration
import com.fiberhome.nas.core.util.time.formatToISO
import com.fiberhome.nas.navigation.AppNavigator
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.util.Date
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Semaphore
import javax.inject.Inject
import javax.inject.Singleton

/**
 * 上传管理器
 * 负责处理文件上传任务，支持文件切片、MD5计算、断点续传
 * 支持限制同时上传的任务数量
 */
@Singleton
class UploadManager @Inject constructor(
    @ApplicationContext private val context: Context,
    private val photoRepository: PhotoRepository,
    private val taskCenterRepository: TaskCenterRepository,
    private val appNavigator: AppNavigator
) {
    companion object {
        private const val TAG = "UploadManager"
        private const val DEFAULT_CHUNK_SIZE = 5 * 1024 * 1024 // 5MB
        private const val MAX_CONCURRENT_UPLOADS = 5 // 最大同时上传任务数
    }

    // 上传任务列表
    private val _uploadTasks = MutableStateFlow<List<UploadTask>>(emptyList())
    val uploadTasks: StateFlow<List<UploadTask>> = _uploadTasks.asStateFlow()

    // 活跃的上传任务Map，taskId -> Job，使用线程安全的ConcurrentHashMap
    private val activeUploads = ConcurrentHashMap<String, Job>()

    // 使用信号量控制并发分片上传数量
    private val chunkUploadSemaphore = Semaphore(MAX_CONCURRENT_UPLOADS)

    // 上传作用域
    private val uploadScope = CoroutineScope(Dispatchers.IO)


    /**
     * 从数据库加载所有上传任务
     * 包括未完成的和已完成的任务
     */
    suspend fun loadTasksFromDatabase() {
        taskCenterRepository.getAllUploadTasks().collectLatest { tasks ->
            _uploadTasks.value = tasks
            // 对于暂停状态的任务，不需要重新启动上传
            // 对于等待和上传中状态的任务，需要重新启动上传
            tasks.filter { it.status == TaskStatus.Waiting || it.status == TaskStatus.Uploading }
                .forEach { task ->
                    // 获取媒体项信息并重新启动上传
                    val file = File(task.filePath)
                    if (file.exists() && file.isFile) {
                        // 创建一个简单的LocalMediaItem对象，包含必要的信息
                        val mediaItem = MediaConverter.uploadTaskToLocalMediaItem(task)
                        // 重新启动上传任务，从当前进度继续
                        startUploadTask(task)
                    } else {
                        // 文件不存在，更新任务状态为失败
                        updateTaskStatus(task.id, TaskStatus.Failed, "文件不存在")
                        updateTaskInDatabase(task.id, TaskStatus.Failed, "文件不存在")
                    }
                }
        }
    }

    /**
     * 上传照片
     *
     * @param mediaItems 要上传的媒体项列表
     * @param deviceAlbum 目标相册
     */
    fun uploadPhotos(mediaItems: List<LocalMediaItem>, deviceAlbum: AlbumInfo) {
        if (mediaItems.isEmpty()) return

        // 创建上传任务并添加到任务列表
        val newTasks = mediaItems.map { mediaItem ->
            // 创建任务项UploadTask
            val uploadTask = MediaConverter.localMediaItemToUploadTask(
                mediaItem,
                deviceAlbum,
                DEFAULT_CHUNK_SIZE
            )
            // 保存任务到数据库
            saveTaskToDatabase(uploadTask)
            // 启动上传任务
            startUploadTask(uploadTask)
            uploadTask
        }

        // 更新任务列表
        _uploadTasks.update { currentTasks -> currentTasks + newTasks }

        // 导航到任务中心
        /*CoroutineScope(Dispatchers.Main).launch {
            appNavigator.navigateTo(TaskCenterRoutes.TASK_CENTER_ROUTE)
        }*/
    }

    /**
     * 启动上传任务
     */
    private fun startUploadTask(task: UploadTask) {
        val job = uploadScope.launch {
            try {
                // 更新任务状态为等待中
                updateTaskStatus(task.id, TaskStatus.Waiting, "等待上传...")
                updateTaskInDatabase(task.id, TaskStatus.Waiting, "等待上传...")

                val file = File(task.filePath)
                if (!file.exists() || !file.isFile) {
                    updateTaskStatus(task.id, TaskStatus.Failed, "文件不存在")
                    updateTaskInDatabase(task.id, TaskStatus.Failed, "文件不存在")
                    return@launch
                }

                // 计算文件MD5
                val fileHash = FileUtils.calculateMD5Coroutine(file)
                if (fileHash.isEmpty()) {
                    updateTaskStatus(task.id, TaskStatus.Failed, "MD5计算失败")
                    updateTaskInDatabase(task.id, TaskStatus.Failed, "MD5计算失败")
                    return@launch
                }

                // 分片上传
                val totalSize = file.length()
                val chunkSize = DEFAULT_CHUNK_SIZE.toLong()
                val totalChunks = (totalSize + chunkSize - 1) / chunkSize

                updateTaskStatus(
                    task.id,
                    TaskStatus.Uploading,
                    "0/${FileUtils.formatFileSize(totalSize)}"
                )
                updateTaskInDatabase(task.id, TaskStatus.Uploading, "开始上传")

                // 上传所有分片
                for (chunkNumber in 0 until totalChunks.toInt()) {
                    // 检查任务是否被取消
                    if (!isActive(task.id)) {
                        return@launch
                    }

                    // 获取信号量，如果没有可用的信号量，将会阻塞直到有信号量可用
                    chunkUploadSemaphore.acquire()

                    val offset = chunkNumber * chunkSize
                    val currentChunkSize = minOf(chunkSize, totalSize - offset)

                    // 计算分片MD5，使用FileUtils中的方法
                    val chunkHash =
                        FileUtils.calculateChunkMD5(file, offset, currentChunkSize) ?: ""
                    if (chunkHash.isEmpty()) {
                        updateTaskStatus(task.id, TaskStatus.Failed, "分片MD5计算失败")
                        updateTaskInDatabase(task.id, TaskStatus.Failed, "分片MD5计算失败")
                        chunkUploadSemaphore.release() // 释放分片信号量
                        return@launch
                    }

                    // 创建分片数据，使用FileUtils中的方法
                    val chunkFile = FileUtils.createTempChunkFile(
                        file,
                        offset,
                        currentChunkSize,
                        context.cacheDir
                    )
                    if (chunkFile == null) {
                        updateTaskStatus(task.id, TaskStatus.Failed, "分片创建失败")
                        updateTaskInDatabase(task.id, TaskStatus.Failed, "分片创建失败")
                        chunkUploadSemaphore.release() // 释放分片信号量
                        return@launch
                    }

                    // 构建上传请求
                    val uploadRequest = UploadRequest(
                        fileName = file.name,
                        fileCreatedAt = Date().formatToISO(),
                        fileModifiedAt = Date().formatToISO(),
                        chunkOffset = offset,
                        chunkSize = currentChunkSize,
                        chunkNumber = chunkNumber,
                        chunkHash = chunkHash,
                        totalChunk = totalChunks.toInt(),
                        totalSize = totalSize,
                        fileHash = fileHash,
                        hashAlgorithm = "MD5",
                        assetData = chunkFile,
                        //media_property
                        deviceAssetId = task.mediaId, //文件唯一标识
                        deviceId = "APP", //APP or WEB
                        isFavorite = task.favorite,
                        duration = task.duration?.formatToDuration(),
                        path = task.uploadPath
                    )

                    // 执行上传
                    ResultHandler.handleResultWithData(
                        scope = uploadScope,
                        flow = photoRepository.uploadPhoto(uploadRequest).asResult(),
                        onData = { res ->
                            // 更新进度
                            val uploadedSize = offset + currentChunkSize

                            // 计算上传速度（简单实现，可以进一步优化）
                            val speedText = if (currentChunkSize > 0) {
                                "${FileUtils.formatFileSize(currentChunkSize)}/s"
                            } else {
                                ""
                            }

                            val progressText = "${FileUtils.formatFileSize(uploadedSize)}/${
                                FileUtils.formatFileSize(totalSize)
                            } $speedText"

                            // 更新内存中的任务进度
                            updateTaskProgress(task.id, progressText)

                            // 更新数据库中的任务进度
                            val updateTask = _uploadTasks.value.find { it.id == task.id }
                            if (updateTask != null) {
                                updateTask.uploadedSize = uploadedSize
                                updateTask.currentChunk = chunkNumber + 1
                                updateTask.labelTip = progressText
                                uploadScope.launch {
                                    updateTaskInDatabase(updateTask)
                                }
                            }
                        },
                        onError = { error, e ->
                            // 上传失败
                            val errorMsg = e?.message ?: "上传失败"
                            updateTaskStatus(task.id, TaskStatus.Failed, errorMsg)

                            // 更新数据库
                            val updateTask = _uploadTasks.value.find { it.id == task.id }
                            if (updateTask != null) {
                                updateTask.status = TaskStatus.Failed
                                updateTask.labelTip = errorMsg
                                updateTask.uploadedSize = offset
                                updateTask.currentChunk = chunkNumber
                                uploadScope.launch {
                                    updateTaskInDatabase(updateTask)
                                }
                            }

                            chunkUploadSemaphore.release() // 释放分片信号量
                            LogUtils.e("上传失败", error)
                        }
                    )

                    // 删除临时分片文件
                    chunkFile.delete()

                    // 释放分片信号量
                    chunkUploadSemaphore.release()
                }

                // 所有分片上传完成
                updateTaskStatus(task.id, TaskStatus.Completed, "上传完成")

                // 更新数据库
                val updateTask = _uploadTasks.value.find { it.id == task.id }
                if (updateTask != null) {
                    updateTask.status = TaskStatus.Completed
                    updateTask.labelTip = "上传完成"
                    updateTask.uploadedSize = totalSize
                    updateTask.currentChunk = totalChunks.toInt()

                    // 更新数据库
                    updateTaskInDatabase(updateTask)
                }

                // 所有分片已完成，不需要额外释放信号量

            } catch (e: Exception) {
                LogUtils.e(TAG, "Upload failed: ${e.message}")
                updateTaskStatus(task.id, TaskStatus.Failed, e.message ?: "上传失败")

                // 更新数据库
                val updateTask = _uploadTasks.value.find { it.id == task.id }
                if (updateTask != null) {
                    updateTask.status = TaskStatus.Failed
                    updateTask.labelTip = e.message ?: "上传失败"

                    // 更新数据库
                    updateTaskInDatabase(updateTask)
                }

                // 异常情况下不需要额外释放信号量，因为每个分片都会单独释放
            } finally {
                // 从活跃任务中移除
                activeUploads.remove(task.id)
            }
        }

        // 添加到活跃任务
        activeUploads[task.id] = job
    }


    /**
     * 保存任务到数据库
     */
    private fun saveTaskToDatabase(uploadTask: UploadTask) {
        uploadScope.launch {
            taskCenterRepository.insertUploadTask(uploadTask)
        }
    }

    /**
     * 更新任务状态
     */
    private fun updateTaskStatus(taskId: String, status: TaskStatus, statusText: String) {
        _uploadTasks.update { tasks ->
            tasks.map { task ->
                if (task.id == taskId) {
                    task.copy(
                        status = status,
                        labelTip = statusText
                    )
                } else {
                    task
                }
            }
        }
    }

    /**
     * 更新任务进度
     */
    private fun updateTaskProgress(taskId: String, progressText: String) {
        _uploadTasks.update { tasks ->
            tasks.map { task ->
                if (task.id == taskId) {
                    task.copy(
                        labelTip = progressText
                    )
                } else {
                    task
                }
            }
        }
    }

    /**
     * 更新数据库中的任务
     * @param task 要更新的上传任务
     */
    private suspend fun updateTaskInDatabase(task: UploadTask) {
        withContext(Dispatchers.IO) {
            try {
                taskCenterRepository.updateUploadTask(task)
            } catch (e: Exception) {
                LogUtils.e(TAG, "Failed to update task in database: ${e.message}")
            }
        }
    }

    /**
     * 更新数据库中的任务状态
     * @param taskId 任务ID
     * @param status 任务状态
     * @param statusText 状态描述文本
     */
    private suspend fun updateTaskInDatabase(
        taskId: String,
        status: TaskStatus,
        statusText: String
    ) {
        val task = _uploadTasks.value.find { it.id == taskId } ?: return
        task.status = status
        task.labelTip = statusText
        updateTaskInDatabase(task)
    }

    /**
     * 暂停任务
     */
    fun pauseTask(taskId: String) {
        val job = activeUploads[taskId]
        job?.cancel()
        activeUploads.remove(taskId)

        // 更新内存中的任务状态
        val task = _uploadTasks.value.find { it.id == taskId } ?: return
        task.status = TaskStatus.Paused
        task.labelTip = "已暂停"

        _uploadTasks.update { tasks ->
            tasks.map { t ->
                if (t.id == taskId) task else t
            }
        }

        // 更新数据库状态
        uploadScope.launch {
            updateTaskInDatabase(task)
        }
    }

    /**
     * 恢复任务
     */
    fun resumeTask(taskId: String) {
        // 检查任务是否存在
        val task = _uploadTasks.value.find { it.id == taskId } ?: return

        // 检查任务是否处于暂停状态
        if (task.status != TaskStatus.Paused) return

        // 检查文件是否存在
        val file = File(task.filePath)
        if (!file.exists() || !file.isFile) {
            // 文件不存在，更新任务状态为失败
            task.status = TaskStatus.Failed
            task.labelTip = "文件不存在"

            _uploadTasks.update { tasks ->
                tasks.map { t ->
                    if (t.id == taskId) task else t
                }
            }

            uploadScope.launch {
                updateTaskInDatabase(task)
            }
            return
        }

        // 更新任务状态为等待中
        task.status = TaskStatus.Waiting
        task.labelTip = "等待中"

        _uploadTasks.update { tasks ->
            tasks.map { t ->
                if (t.id == taskId) task else t
            }
        }

        // 更新数据库状态
        uploadScope.launch {
            updateTaskInDatabase(task)
            // 重新开始上传任务
            startUploadTask(task)
        }
    }

    /**
     * 取消任务
     */
    fun cancelTask(taskId: String) {
        val job = activeUploads[taskId]
        job?.cancel()
        activeUploads.remove(taskId)

        // 从内存中移除任务
        _uploadTasks.update { tasks ->
            tasks.filter { it.id != taskId }
        }

        // 从数据库删除任务
        uploadScope.launch {
            try {
                taskCenterRepository.deleteUploadTask(taskId)
            } catch (e: Exception) {
                LogUtils.e(TAG, "Failed to delete task from database: ${e.message}")
            }
        }
    }

    /**
     * 检查任务是否活跃
     * @param taskId 任务ID
     * @return 任务是否活跃
     */
    private fun isActive(taskId: String): Boolean {
        val job = activeUploads[taskId] ?: return false
        return job.isActive
    }
}